import json

from odoo import api, models, fields, _
import logging
import requests

from odoo.api import ondelete
from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__)
from datetime import timedelta


class MrpProduction(models.Model):
    _name = 'mrp.production'
    _inherit = ['mrp.production', 's.mes.upload']

    def _compute_s_picking_done(self):
        for record in self:
            picking = record.picking_ids.filtered(lambda x: x.state == 'done' and x.picking_type_id.barcode=='WTT-CB')
            if picking and all(picking.mapped('s_mes_lock')):
                record.s_picking_done01 = True
            else:
                record.s_picking_done01 = False

    s_mes_lock = fields.Boolean(string='已同步MES', help='同步mes的工单不允许在odoo过数')
    s_is_workorder = fields.Boolean(string='是否已经过数')
    s_picking_done01 = fields.Boolean(string='已发料同步MES', compute='_compute_s_picking_done')
    # s_picking_done02 = fields.Boolean(string='已发料未同步MES', compute='_compute_s_picking_done')
    s_split_origin = fields.Char(string='拆分原单据')

    def get_mes_token(self):
        return self.env['s.mes.login'].sudo().get_mes_token()

    def get_mes_url(self):
        """url"""
        url = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.updateImsData')]).s_value
        return url

    def get_mes_doctype(self, param=None):
        """mes方法名"""
        if not param:
            return None
        else:
            mes_ = self.env['s.api.config_parameter'].search([('s_key', '=', param)])
            return mes_[0].s_value if mes_ else None

    def get_mes_enabled(self, param=None):
        """控制接口是否开启"""
        if not param:
            return None
        else:
            mes_ = self.env['s.api.config_parameter'].search([('s_key', '=', param)])
            return mes_[0].s_value if mes_ else None

    def _split_productions_progress(self, amounts=False):
        """拆分订单"""
        production_to_backorders = super(MrpProduction, self)._split_productions_progress(amounts)
        production_to_backorders.write({'s_mes_lock': False, 's_split_origin': self.name})
        # for production in production_to_backorders.filtered(lambda x: not x._get_sources()):
            # production.with_delay(description="拆分订单推送mes").action_mes_production(split=True)
            # production.with_delay(description="拆分订单推送mes").action_split_production()
            # production.s_mes_lock = False
        self._cron_split_production(production_to_backorders)
        return production_to_backorders

    def action_mes_production(self, login_list=[], split=False):
        """手动推送工单到mes"""
        self.ensure_one()
        mes_enabled = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.enabled')]).s_value  # 表示开启了MES系统传输
        url = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.updateImsData')]).s_value
        mes_flag_time = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.flag_date')], limit=1).s_value

        if split:
            pass
        elif not login_list or self.env.user.login not in login_list:
            raise ValidationError(f'当前账户不允许执行推送mes操作，请使用【{",".join(login_list)}】')
        if not mes_enabled:
            raise ValidationError('推送接口已关闭')
        if self._get_sources():
            raise ValidationError('内层工单不允许单独推送')
        if not mes_flag_time:
            raise ValidationError('未配置时间节点')
        if self.state not in ['draft', 'confirmed', 'progress']:
            raise ValidationError(f'当前工单状态不允许推送: {self.state}')
        if fields.Datetime.to_string(self.create_date) < mes_flag_time:
            raise ValidationError(f'当前工单创建时间{fields.Datetime.to_string(self.create_date)}晚于接口设置时间节点{mes_flag_time}')
        if self.s_split_origin:
            raise ValidationError('拆分工单不能手动推送，请等待系统自动同步(2min)')
        if self.s_is_workorder:
            raise ValidationError('已过数工单不能推送')
        order = self.env['sale.order'].sudo().search([('name', 'in', self.origin.split(','))], limit=1)
        model = 'sale.order'
        if not order:
            model = 's.research.and.development.order'
            order = self.env['s.research.and.development.order'].sudo().search([('name', 'in', self.origin.split(','))], limit=1)
        if not order:
            raise ValidationError('请检查原单据是否正确，目前只允许推送研发投料和销售投料的工单')
        # if len(order) > 1:
        #     raise ValidationError(f"工单原单据数>1请检查数据合法性: {','.join(order.mapped('name'))}")
        production = self
        if model == 'sale.order':
            order.post_mes_async(url, production)
        else:
            order.post_mes_async(production)

    def _cron_mes_production(self):
        """定时任务轮训发送mes工单"""
        mes_enabled = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.enabled')]).s_value  # 表示开启了MES系统传输
        url = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.updateImsData')]).s_value
        mes_flag_time = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.flag_date')], limit=1).s_value
        pass_categ = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.pass_categ')], limit=1).s_value
        pass_categ_list = []
        if pass_categ:
            pass_categ_list = pass_categ.split(',')
        production_ids = self.env['mrp.production'].search([('create_date', '>=', mes_flag_time),
                                                            ('s_mes_lock', '=', False),
                                                            ('s_is_workorder', '=', False),
                                                            ('state', 'in', ['draft', 'confirmed', 'progress'])])
        if pass_categ_list:
            production_ids = production_ids.filtered(lambda x: not x._get_sources() and not x.s_is_workorder and not x.s_split_origin and x.product_id.categ_id.code not in pass_categ_list)
        else:
            production_ids = production_ids.filtered(lambda x: not x._get_sources() and not x.s_is_workorder and not x.s_split_origin)

        if not mes_enabled:
            raise ValidationError('推送接口已关闭')
        for production in production_ids:
            try:
                order = self.env['sale.order'].sudo().search([('name', 'in', production.origin.split(','))])
                model = 'sale.order'
                if not order:
                    model = 's.research.and.development.order'
                    order = self.env['s.research.and.development.order'].sudo().search([('name', 'in', production.origin.split(','))])
                if not order:
                    raise ValidationError('请检查原单据是否正确，目前只允许推送研发投料和销售投料的工单')
                # if len(order) > 1:
                #     raise ValidationError(f"工单原单据数>1请检查数据合法性: {','.join(order.mapped('name'))}")
                if model == 'sale.order':
                    order.post_mes_async(url, production)
                else:
                    order.post_mes_async(production)
                _logger.info(f'同步mes工单：{production.name}')
            except Exception as e:
                self.env['api.records'].create([{
                    'doc_type': 'API_SO',
                    'api_route': f'定时任务推送记录: {production.name}',
                    'api_params': '',
                    'result_json': str(e),
                    'state': 'fail'
                }])

    def _get_layer_type(self, production):
        product_name = production.product_id.name
        # 对不规则产品进程处理 W02L600009A0-1-2/3, W02L600009A0-2/3
        if '-' in product_name and product_name.split('-')[1] in ['1', '2']:
            mo = product_name.split('-')
            layer_type = mo[-1] if len(mo) - 1 > 1 else '0'
        elif '-' in product_name and product_name.split('-')[1] not in ['1', '2']:
            mo = product_name.split('-')
            layer_type = mo[1] if len(mo) > 1 else '0'
        else:
            layer_type = '0'
        return layer_type

    def _cron_split_production(self, production_ids=None):
        """定时任务轮训发送mes 拆分工单"""
        # url = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.updateImsData')]).s_value
        mes_flag_time = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.flag_date')], limit=1).s_value
        pass_categ = self.env['s.api.config_parameter'].search([('s_key', '=', 'mes.pass_categ')], limit=1).s_value
        pass_categ_list = []
        if pass_categ:
            pass_categ_list = pass_categ.split(',')
        oncommit = False
        if not production_ids:
            production_ids = self.env['mrp.production'].search([('create_date', '>=', mes_flag_time),
                                                                ('s_mes_lock', '=', False),
                                                                ('s_split_origin', '!=', False),
                                                                ('state', 'in', ['draft', 'confirmed', 'progress'])])
        else:
            oncommit = True


        if pass_categ_list:
            production_ids = production_ids.filtered(lambda x: not x._get_sources() and x.product_id.categ_id.code not in pass_categ_list)
        else:
            production_ids = production_ids.filtered(lambda x: not x._get_sources())
        try:
            data_info, all_production = self.s_cron_split(production_ids)
        except Exception as e:
            data_info, all_production = [], []
            self.env['api.records'].create([{
                'doc_type': 'API_MO_MULT_SPLIT',
                'api_route': f'推送拆分工单',
                'api_params': json.dumps(data_info),
                'result_json': str(e),
                'state': 'fail'
            }])

        data = {
            "docType": "API_MO_MULT_SPLIT",
            "updateType": "UPDATE",
            "data": data_info
        }
        result = self.upload_data(data)
        if result and result.get('resultCode') == '0000':
            for p in all_production:
                p.write({'s_mes_lock': True})
        elif oncommit and result and result.get('resultCode') != '0000':
            raise ValidationError(f'拆分订单推送MES失败，请联系系统管理员\n{str(result)}')

    def s_cron_split(self, production_ids):
        data_info = []
        all_production = []
        for production in production_ids:
            origin = self.env['mrp.production'].search([('name', '=', production.s_split_origin)], limit=1)

            if production == origin : continue
            else:
                # value_ps = wo.value_pnl / wo.value_set
                # i.qty_produced_set = i.qty_produced_pnl * value_ps
                # 获取全部内层start
                children_ids = [production]
                visited = [production]
                prod = visited[0]
                while visited and visited.pop(0):
                    children_ids.extend([p for p in prod._get_children()])
                    visited.extend([p for p in prod._get_children()])
                    if visited:
                        prod = visited[0]
                # # end

                # 获取原单据全部内层start-[兼容了cron]
                origin_ids = [origin]
                origin_visited = [origin]
                old_prod = origin_visited[0]
                while origin_visited and origin_visited.pop(0):
                    origin_ids.extend([p for p in old_prod._get_children()])
                    origin_visited.extend([p for p in old_prod._get_children()])
                    if origin_visited:
                        old_prod = origin_visited[0]
                # end

                data_info.append({
                    'suit_code': production.name,
                    'reason': 'None',
                    'mo_list': [{
                        'mo_code': p.name,
                        'layer': self._get_layer_type(p),
                        "set_qty": p.panel_qty * (p.s_value_pnl/p.s_value_set),  # set数量sum(mo_list)
                        "pnl_qty": p.panel_qty,  # pnl数量sum(mo_list)
                        "pcs_qty": p.product_qty,  # PCS数量
                    } for p in origin_ids if p.state != 'cancel'],
                    'new_mo_list': [{
                        'mo_code': p.name,
                        'layer': self._get_layer_type(p),
                        "set_qty": p.panel_qty * (p.s_value_pnl/p.s_value_set),  # set数量sum(mo_list)
                        "pnl_qty": p.panel_qty,  # pnl数量sum(mo_list)
                        "pcs_qty": p.product_qty,  # PCS数量
                    } for p in children_ids]
                })
                all_production.extend(children_ids)
                all_production.extend(origin_ids)
        return data_info, list(set(all_production))

    def _cron_delete_log(self):
        """删除前一天失败的日志"""
        today = fields.Datetime.now()
        # 减去一天
        previous_day = today - timedelta(days=3)
        previous_day_str = fields.Datetime.to_string(previous_day)
        records = self.env['api.records'].search([('create_date', '<', previous_day_str),
                                                  ('doc_type', '=', 'API_SO'),
                                                  ('state', '=', 'fail')])
        records.unlink()

    def button_scrap(self):
        if self.s_mes_lock:
            raise ValidationError('请在MES中进行报废')
        return super().button_scrap()


class MesWrokcenter(models.Model):
    _inherit = 'mrp.workcenter'

    def cron_all(self):
        records = self.env['mrp.workcenter'].sudo().search([])
        for rec in records:
            rec.workcenter_upload_mes()

    @api.model_create_multi
    def create(self, vals_list):
        result = super().create(vals_list)
        for rec in result:
            rec.workcenter_upload_mes()
        return result

    def write(self, vals):
        result = super().write(vals)
        self.workcenter_upload_mes()
        return result

    def workcenter_upload_mes(self):
        """
        工序信息上传 MES
        """
        workcenter_list = []
        for record in self:
            workcenter_list.append({
                "org_id": "0001",  # 组织编码
                "wp_code": record.code,  # 工序编码
                "wp_name": record.name,  # 工序名称
                "norm_date": 0,  # 标准时间（小时）
                "back_qty": 0,  # 返工上限
                "norm_qty": record.oee_target,  # 标准良率（%）
                "sign_code": "",  # NCN前缀
                "wp_component_type": 0,  # 制程组成类型 0:产线 1:设备组 2:设备
                # 工序属性 1:普通 2:开料 3:内层前处理 4:棕化 5:预叠 6:字符 7:成型 8:包装 9:AOI 10:钻孔 11:VRS 12:电测 13:压合 14:内层曝光 15:外层曝光 16:阻焊 17:电镀 18:沉铜
                "wp_property": 0,
                "wp_unit": 4,  # 单位 1:批次 2:PNL 3:SET 4:PCS
                "shot_stat": 0,  # 钻针时机
                "cut_stat": 0,  # 锣刀时机
                "flat_stat": 0,  # 铝片时机
                "pp_stat": 0,  # PP时机
                "plate_stat": 0,  # 垫板时机
                "capacity_type": 0,  # 产能类型 1:无 2:天 3:数量
                "wp_date": "s",  # 生产日期  <= 1 字符
                "wp_stat": 0,  # 工序状态 1:转入 2:上机 3:下机 4:转出
                "first_hz": 0,  # 首件频率 1:批次 2:产品 3:班次
                "first_type": 0,  # 首件类型 1:动态 2:静态
                "first_qty": 0,  # 首件数量
                "fqc_hz": 0,  # 成品频率 1:批次 2:产品
                "smoke_date": 0,  # 巡检范围 1:批次 2:产品
                "smoke_type": 0,  # 巡检类型 1:小时 2:天 3:自定义
                "pass_qty": 0,  # 良率数量
                "is_spout": "N",  # 镭射状态 Y，N
                "is_valid": "Y",  # 启用状态 Y，N
                "change_stat": "N",
                "show_stat": "N",
                "top_stat": "Y" if record.is_enter_bcode else 'N',
                "down_stat": "Y" if record.is_enter_bcode else 'N',
                "is_notify": "Y" if record.is_enter_bcode else 'N',
                "notify_point": 1,
                "remark": "0"  # 备注
            })
        data = {
            "docType": "BS_WP",
            "updateType": "UPDATE",
            "data": workcenter_list
        }
        self.env['s.mes.upload'].upload_data(data=data)
